package net.sf.nlp.ltag.parser;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.sf.nlp.ltag.data.LTAGNode;
import net.sf.nlp.ltag.data.LTAGTree;
import net.sf.nlp.ltag.data.Operator;

public class ParserTree 
{
	private LTAGTree tree;
	private double freq;
	
	public ParserTree(LTAGTree tree, double freq)
	{
		this.tree = tree;
		this.freq = freq;
	}
	
	public LTAGTree getTree() {
		return tree;
	}
	public void setTree(LTAGTree tree) {
		this.tree = tree;
	}

	public double getFreq() {
		return freq;
	}

	public static List<Operator> copyOperatorHistory(List<Operator> operatorHistory)
	{
		List<Operator> copyOperators = new ArrayList<Operator>();
		Map<LTAGTree, LTAGTree> treeMap = new HashMap<LTAGTree, LTAGTree>();
		
		for (int i = 0; i < operatorHistory.size(); i++)
		{
			Operator op = operatorHistory.get(i);
			
			LTAGTree tree1 = op.getTree1();
			LTAGTree tree2 = op.getTree2();
			LTAGNode opNode = op.getTree1Node();
			
			LTAGTree clonedTree1 = treeMap.get(tree1);
			LTAGTree clonedTree2 = treeMap.get(tree2);
			
			if (clonedTree1 == null)
			{
				clonedTree1 = tree1.clone();
				treeMap.put(tree1, clonedTree1);
			}
			
			if (clonedTree2 == null)
			{
				clonedTree2 = tree2.clone();
				treeMap.put(tree2, clonedTree2);
			}
			
			LTAGNode clonedNode1 = clonedTree1.getNodeByLocation(opNode.getLocation());
			
			Operator cloneOp = new Operator(clonedTree1, clonedTree2, op.getOperator(), clonedNode1);
			copyOperators.add(cloneOp);
		}
		
		return copyOperators;
	}
	
	public static ParserTree build(LTAGState state)
	{
		List<Operator> operatorHistory = copyOperatorHistory(state.getOperatorHistory());
		
		LTAGTree tree = null;
		LTAGNode parent = null;
		int index;
		
		for (int i = 0; i < operatorHistory.size(); i++)
		{
			Operator op = operatorHistory.get(i);
			
			LTAGTree tree1 = op.getTree1();
			LTAGTree tree2 = op.getTree2();
			LTAGNode opNode = op.getTree1Node();
			
			if (i == 0)
				tree = tree1;
			
			if ("$".equals(op.getOperator()))
			{
				parent = opNode.getParent();
				index = parent.getChildren().indexOf(opNode);
				parent.getChildren().set(index, tree2.getRoot());
				tree2.getRoot().setParent(parent);
			}
			else
			{
				parent = opNode.getParent();
				if (parent != null)
				{
					index = parent.getChildren().indexOf(opNode);
					parent.getChildren().set(index, tree2.getRoot());
					tree2.getRoot().setParent(parent);
				}
				else if (tree == tree1)
					tree = tree2;
				
				LTAGNode foot = tree2.getFoot();
				parent = foot.getParent();
				index = parent.getChildren().indexOf(foot);
				parent.getChildren().set(index, opNode);
				opNode.setParent(parent);
			}
		}
		
		tree.generateNodeLocation();
		
		return new ParserTree(tree, state.getFreq());
	}
}
